#include <iostream>
using namespace std;
//#include "mpp_itc_dec_interface.h"
//#include "mpp_itc_enc_interface.h"
#include <xf86drmMode.h>
#include <xf86drm.h>
#include <errno.h>
#include <mpp_common.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iostream>     
#include <thread>         
//#include "../mpp_itc_display_interface/mpp_itc_rga.h"

#define DEC_LIB_DIR "../../../libs/libmpp_itc_dec_interface.so"
#define ENC_LIB_DIR "../../../libs/libmpp_itc_enc_interface.so"
#define MAX_CH           (8)

typedef      MPP_ITC_DEC_FUNTION * (* FUNC_MPP_IMAGE_DECODE)(void);
typedef      void (* FUNC_MPP_IMAGE_DECODE_DISTROY)(MPP_ITC_DEC_FUNTION * dec);

typedef      MPP_IMAGE_PROCESS_T * (* FUNC_MPP_IMAGE_PROCESS_CREATE)(void);
typedef      void (* FUNC_MPP_IMAGE_PROCESS_DESTROY)(MPP_IMAGE_PROCESS_T * dec);

typedef      MPP_ITC_DISPLAY_FUNTION_T * (*CREATE_DISPLAY_PROCESS)(void);
typedef      void (*DISPLAY_PROCESS_DESTROY)(MPP_ITC_DISPLAY_FUNTION_T * display);

typedef struct
{
    void                                        *dec_handle;
    MPP_ITC_DEC_FUNTION        *dec_fun;

    MPP_IMAGE_PROCESS_T        *process_image;

    FUNC_MPP_IMAGE_DECODE create_decode;
    FUNC_MPP_IMAGE_DECODE_DISTROY distroy_decode;
    uint32_t                                    index;
    uint8_t                                      *rga_buf;
    
    void *ctx;
}DECODE_STRUCT;


MPP_SURFACE_ATTR *surface = NULL ;
MPP_ITC_DISPLAY_FUNTION_T *display_fun = NULL; 
DECODE_STRUCT  decode_arg[MAX_CH];
MPP_SURFACE_RECT_S  rect[9];
thread                  *_decode_thread[MAX_CH]; 
static void _decode_frame_callback(void *ctx ,void *usr_arg,int fd,uint8_t *fame,uint32_t length)
{

        DECODE_STRUCT *_decode_arg = (DECODE_STRUCT *)usr_arg;
        IMAGE_PROCESS_INFO_T   processInfo ;
        if(!_decode_arg)
            return ;
        printf("第%d路 解码长度 %d fd=%d   ctx %p\n",_decode_arg->index,length,fd,ctx);
        // static uint8_t flg = 0;&& flg == 0  
        if(_decode_arg->process_image  ){//&&( _decode_arg->index == 0  ||  _decode_arg->index == 1 )
             display_fun->mpp_surface_rect_draw(display_fun->cxt,surface,_decode_arg->index,fame,1920,1080);

        }
    
}


static void decode_thread(void *arg)
{
    DECODE_STRUCT *_decode_arg = (DECODE_STRUCT *)arg;
    if(!_decode_arg)
        return ;
    FUNC_MPP_IMAGE_DECODE create_decode = NULL;
    FUNC_MPP_IMAGE_DECODE_DISTROY distroy_decode = NULL;
    MPP_DECODE_BUF   *decode_buf= NULL;
    create_decode = (FUNC_MPP_IMAGE_DECODE)dlsym(_decode_arg->dec_handle, "create_decode");
    distroy_decode = (FUNC_MPP_IMAGE_DECODE_DISTROY)dlsym(_decode_arg->dec_handle, "destroy");
    cout<<"index "<<_decode_arg->index<<endl;

    if( _decode_arg->process_image)
        cout<<"version: "<< _decode_arg->process_image->image_process_version()<<endl;
    else
       return ;
   


    if(create_decode){
        _decode_arg->dec_fun = create_decode();
        if(_decode_arg->dec_fun){
            _decode_arg->ctx = _decode_arg->dec_fun->ctx;
            // cout<<"获取解码器成功"<< static_cast<const void *>(_decode_arg->dec_fun) << endl;
            printf("获取解码器成功 %p \n", _decode_arg->ctx);
            if(   MPP_RET_CODE_OK != _decode_arg->dec_fun->mpp_dec_init(_decode_arg->dec_fun->ctx,MPP_TYPE_H265,MPP_FRAME_TYPE_YUV420SP,1080,1920,1080,1920,0)   ){//MPP_TYPE_H264
                cout<<"解码器初始化失败"<<endl;
                goto err;
            }


            decode_buf=  _decode_arg->dec_fun->mpp_dec_create_buffer(_decode_arg->dec_fun->ctx);
            if(!decode_buf){
                cout<<"解码器获取空间失败"<<endl;
                goto err;
            }
            const uint32_t  Max_Length = decode_buf->length;
            cout<<"内存地址:"<<(int*)decode_buf->addr<<"  可写入长度:"<<decode_buf->length<<endl;
            _decode_arg->dec_fun->mpp_dec_regist_done_callback(_decode_arg->dec_fun->ctx,_decode_arg,_decode_frame_callback);


            FILE *h264File = NULL;
            uint32_t length = 0;
            bool isEnd = false;
            h264File = fopen("../../../res/test_1080p.h265","r");//1080P60.h265    
            if(h264File){
                    cout<<"第"<<_decode_arg->index<<"路打开源文件成功"<<endl;
                     while(isEnd == false){
                            length = fread(decode_buf->addr,1,Max_Length,h264File);
                            if(length <  Max_Length)
                                isEnd = true;
                            _decode_arg->dec_fun->mpp_dec_set_buffer_length(_decode_arg->dec_fun->ctx,decode_buf,length);    
                            _decode_arg->dec_fun->mpp_dec_push(_decode_arg->dec_fun->ctx,decode_buf,isEnd);
                            
                    }
                    fclose(h264File);
            }
            _decode_arg->dec_fun->mpp_dec_detroy_buffer(_decode_arg->dec_fun->ctx,&decode_buf);
          
        }
    }



    err:
        if(_decode_arg->dec_handle){
            if(_decode_arg->dec_fun){
                _decode_arg->dec_fun->mpp_dec_deinit(_decode_arg->dec_fun->ctx);
            }
    }


}

int main(int argc,char* argv[])
{
    
    void *dec_handle = NULL, *image_handle=NULL;
    dec_handle = dlopen(DEC_LIB_DIR,RTLD_LAZY | RTLD_GLOBAL);
    if(!dec_handle){
        cout<<"解码器打开失败"<<endl;
        return -1;
    }
    image_handle = dlopen("../../../libs/libmpp_itc_display_interface.so", RTLD_LAZY);//../../../libs/libmpp_itc_display_interface.so
    printf("rga_handle %p\n",image_handle);
    if (!image_handle){
        printf("dlopen../../../libs/libmpp_itc_display_interface.so failed\n");
        return -1;
    }else{
        cout<<"成功打开 "<<" ../../../libs/libmpp_itc_display_interface.so"<<endl;
    }


    
    CREATE_DISPLAY_PROCESS display_process = NULL;
    DISPLAY_PROCESS_DESTROY display_process_destroy = NULL;
    

    FUNC_MPP_IMAGE_PROCESS_CREATE image_process_handle = NULL;
    FUNC_MPP_IMAGE_PROCESS_DESTROY image_destroy = NULL;

    display_process  = (CREATE_DISPLAY_PROCESS)dlsym(image_handle,"create_display_process");
    display_process_destroy =  (DISPLAY_PROCESS_DESTROY)dlsym(image_handle,"display_process_destroy");


    image_process_handle = (FUNC_MPP_IMAGE_PROCESS_CREATE)dlsym(image_handle, "create_image_process");
    image_destroy = (FUNC_MPP_IMAGE_PROCESS_DESTROY)dlsym(image_handle, "image_process_destroy");

    if(display_process)
        display_fun = display_process();
    if(display_fun){
        display_fun->mpp_display_init(display_fun->cxt,1920,1080,60);                                                                           //--先设置屏幕分辨率
        surface = display_fun->mpp_create_surface(display_fun->cxt,MPP_FRAME_TYPE_YUV420SP,0,0,1920,1080);    //--创建一个surface
        display_fun->mpp_surface_destroy_rects(display_fun->cxt,surface);                                                                    // --先销毁掉宫格画面

        rect[0].s32X = 0;
        rect[0].s32Y = 0;
        rect[0].u32Width = 1920/3;
        rect[0].u32Height = 1080/3;

        rect[1].s32X = 1920/3;
        rect[1].s32Y = 0;
        rect[1].u32Width = 1920/3;
        rect[1].u32Height = 1080/3;

        rect[2].s32X = 1920/3+1920/3;
        rect[2].s32Y = 0;
        rect[2].u32Width = 1920/3;
        rect[2].u32Height = 1080/3;

        rect[3].s32X = 0;
        rect[3].s32Y = 1080/3;
        rect[3].u32Width = 1920/3;
        rect[3].u32Height = 1080/3;

        rect[4].s32X = 1920/3;
        rect[4].s32Y = 1080/3;
        rect[4].u32Width = 1920/3;
        rect[4].u32Height = 1080/3;


        rect[5].s32X = 1920/3+1920/3;
        rect[5].s32Y = 1080/3;
        rect[5].u32Width = 1920/3;
        rect[5].u32Height = 1080/3;



        rect[6].s32X = 0;
        rect[6].s32Y = 1080/3+1080/3;
        rect[6].u32Width = 1920/3;
        rect[6].u32Height = 1080/3;


        rect[7].s32X = 1920/3;
        rect[7].s32Y = 1080/3+1080/3;
        rect[7].u32Width = 1920/3;
        rect[7].u32Height = 1080/3;


        rect[8].s32X = 1920/3+1920/3;
        rect[8].s32Y = 1080/3+1080/3;
        rect[8].u32Width = 1920/3;
        rect[8].u32Height = 1080/3;

        display_fun->mpp_surface_create_rects(display_fun->cxt,surface,9,rect);                                                                    // --先销毁掉宫格画面
    }
    MPP_IMAGE_PROCESS_T        * tmp_pro = image_process_handle();


    memset(&decode_arg,0x00,MAX_CH*sizeof(DECODE_STRUCT));
  
    for(int i = 0;i<MAX_CH;i++){
        decode_arg[i].index = i;
        decode_arg[i].process_image = tmp_pro;
        decode_arg[i].rga_buf   = new uint8_t [(1920/2)*(1080/2)*4];
        decode_arg[i].dec_handle = dec_handle;
        _decode_thread[i] = new thread(decode_thread,&decode_arg[i]);
        //thread decode(decode_thread,&decode_arg[i]);
        //decode.detach();
    }

    getchar();
   
    for(int i = 0 ;i<MAX_CH;i++){
         _decode_thread[i]->join();   
         delete _decode_thread[i];
         if(decode_arg[i].rga_buf)
            delete decode_arg[i].rga_buf;
    }

    


   err:
    if(dec_handle){
     
        dlclose(dec_handle);
    }


    if(image_handle) {

#if 0
        if(process){
            process->image_process_deInit(process->ctx);
            image_destroy(process);
        }
#endif

        if(display_fun){
            display_fun->mpp_display_deinit(display_fun->cxt);
            display_fun->mpp_surface_destroy_rects(display_fun->cxt,surface);  
            display_fun->mpp_destroy_surface(display_fun->cxt,surface);  
            display_process_destroy(display_fun);
        }
        // if(tmp_pro){
        //     image_destroy(tmp_pro);
        // }
        
        dlclose(image_handle);
    }

        


    return 0;
}
